#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/wait.h>

using namespace std;

//我的全局指令表
const int gargnum=64;
char* gargv[gargnum];
int gargc=0;

//我的全局地址表
//没有"PWD="
const int basesize=1024;
char pwd[basesize];
//有"PWD="
char my_pwd[basesize];

//我的全局环境变量表
const int genvnum=64;
char* genv[genvnum];

//上一指令错误返回值
int lastcode=0;

void InitEnv(){
    extern char** environ;
    int index=0;
//如果文件类型（filetype）被误判（如 .cc 文件被识别为 HTML）
//"<"or">"可能会被判定为HTML标签，
//Vim 会使用错误的语法高亮规则。
   while(genv[index]&&index<=genvnum-2){
        genv[index]=(char*)malloc(strlen(environ[index])+1);
        sprintf(genv[index],"%s",environ[index]);
        ++index;
    }
    genv[index]=nullptr;
}

void DeletEnv(){
    int index=0;
    while(genv[index]){
        free(genv[index]);
        ++index;
    }
}

string GetUser(){
    string user=getenv("USER");
    return user.empty()?"None":user;
}

string GetHostname(){
    string hostname=getenv("HOSTNAME");
    return hostname.empty()?"None":hostname;
}

string GetDir(){
    if(!getcwd(pwd,basesize))
        return "None";

    snprintf(my_pwd,basesize,"PWD=%s",pwd);
    return pwd;
}

string GetLastDir(){
    string last=GetDir();
    if(last=="/"||last=="None")
        return last;    
    
    size_t pos=last.rfind('/');
    if(pos==string::npos)
        return last;

    return last.substr(pos+1);
}

void PrintCommand(){
    printf("[%s@%s %s]#",
            GetUser().c_str(),
            GetHostname().c_str(),
            GetLastDir().c_str());
}

bool GetCommand(char* buffer,int size){
    char* result=fgets(buffer,size,stdin);
    if(!result)
        return false;

    //一定要记住把\n换成0
    buffer[strlen(buffer)-1]=0;
    //注意只有\n的情况
    if(!strlen(buffer))
        return false;
    return true;
}

void ParseCommand(char* buffer){
   memset(gargv,0,gargnum);

   int gargc=0;
   gargv[gargc++]=strtok(buffer," ");
   while((bool)(gargv[gargc++]=strtok(nullptr," ")));
   --gargc;
}

void test(){
    for(int i=0;gargv[i];i++){
        printf("%s ",gargv[i]);
    }
}
bool AddEnv(const string& var){
    int pos=var.find("=");
    string name=var.substr(0,pos+1);
    int index=0;
    while(index<=genvnum-3&&genv[index]){
        if(strncmp(genv[index],name.c_str(),name.size())){
            free(genv[index]);
            break;
        }
        ++index;
    }

    if(index<=genvnum-2){
        if(!genv[index]){
            genv[index+1]=0;
        }

        //替换or末尾加值
        genv[index]=(char*)malloc(var.size()+1);
        sprintf(genv[index],"%s",var.c_str());
        return true;
    }

    return false;
}

bool ChDir(const string& dir){
    if(chdir(dir.c_str())){//成功返回0
        perror("chdir failed\n");
        return false;
    }

    if(!getcwd(pwd,basesize)){
        perror("getcwd failed\n");
        return false;
    }

    snprintf(my_pwd,basesize,"PWD=%s",pwd);
    if(!AddEnv(my_pwd)){
        perror("AddEnv failed\n");
        return false;
    }
    return true;
}

bool MyEcho(char** com);
//内接命令：chdir(改变当前进程路径)
//          export(可设计当前环境变量)
//          echo(输出当前环境变量)
//          env
bool CheckAndBuildInerCom(){
    if(strcmp(gargv[0],"cd")==0){
        if(gargc==2){
            if(!ChDir(gargv[1]))
                lastcode=1;
        }
        else
            lastcode=1;
        return true;
    }
    else if(strcmp(gargv[0],"export")==0){
        if(gargc==2){
            if(!AddEnv(gargv[1]))
                lastcode=2;
        }
       else 
            lastcode=2;
        return true;
    }
    else if(strcmp(gargv[0],"echo")==0){
        if(gargc==2){
            if(!MyEcho(gargv))
                lastcode=3;        
        }
        else 
            lastcode=3;
        return true;
    }
    else if(strcmp(gargv[0],"env")==0){
        if(gargc==2)
            printf("%s",getenv(gargv[1])?getenv(gargv[1]):"None");
        else 
            lastcode=4;
        return true;
    }
    return false;
}
void ExecuteCommand();
int main(){
    char command_buffer[basesize];
    InitEnv();
    while(1){
        PrintCommand();
        if(!GetCommand(command_buffer,basesize))
            continue;

        ParseCommand(command_buffer);
        //test();
        if(CheckAndBuildInerCom())
            continue;

        ExecuteCommand();
    }
    DeletEnv();
    return 0;
}
